/************************************************************************
This file is part of Polar4linux
Copyright (C) 2010-2011 Eric jrdn2
Portions Copyright (C) 2007 Matti Juvonen <mpj@iki.fi> (RS400 Tools)
Portions Copyright (C) 2006 Jani Hursti <jani.hursti@hut.fi>,
Portions Copyright (C) 2001-2003 Tom Oliveira e Silva

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
************************************************************************/

#include "polarCalendar.h"

class SimpleItem : public QGraphicsItem
{
	public:
	SimpleItem(const int _nbEx, const unsigned int _x,const unsigned int _y, const unsigned int _wx,
						 const unsigned int _wy,const int _date,QBrush _brush)
	{
		nbEx=_nbEx;
		currentEx=1;
		x=_x;
		y=_y;
		wx=_wx;
		wy=_wy;
		date=_date;
		brush=_brush;
		is_selected=false;
	}
	
	QRectF boundingRect() const
	{
		qreal penWidth = 1;
		if (is_selected==0 || nbEx==0 ) return QRectF(x - penWidth / 2, y - penWidth / 2, wx + penWidth, wy + penWidth);
		else return QRectF(x - penWidth / 2, y - penWidth / 2, 12*(nbEx-1)+wx + penWidth, wy + penWidth);
	}

	int setCurrentExercise(QPointF &pt)
	{
		int posX=(pt.x()-x)-(wx/2-5);
		currentEx=posX/12;
		if (currentEx<1) currentEx=1;
		if (currentEx>=nbEx) currentEx=nbEx;
		return currentEx;
	}
	
	bool isOn(QPointF &pt)
	{
		if (is_selected==0) return (pt.x()>x && pt.x()<x+wx && pt.y()>y && pt.y()<y+wy);
		else return (pt.x()>x && pt.x()<x+wx+12*(nbEx-1) && pt.y()>y && pt.y()<y+wy);
	}
	
	void select()
	{
		moveBy(10,10);
		setZValue(2);
		is_selected=true;
	}
	
	void release()
	{
		if (is_selected==true)
		{
			moveBy(-10,-10);
			is_selected=false;
			setZValue(1);
		}
	}
	
	void paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
	{
		painter-> setBrush(brush);
		if (is_selected == 0 || nbEx == 0)
		{
			painter-> drawRoundedRect(x, y, wx, wy, 10, 10);
			painter-> drawText ( wx/2-5+x, wy/2+y, QString::number(date));
		}
		else
		{
			painter-> drawRoundedRect(x, y, wx+12*(nbEx-1), wy, 10, 10);
			for (unsigned int i=1;i<=nbEx;i++)
			{
				if (i==currentEx) painter->setPen(Qt::white);
				else painter->setPen(Qt::black);
				painter-> drawText ( wx/2-5+x+12*(i-1), wy/2+y, QString::number(i));
			}
		}
	}
	
	bool is_selected;
	unsigned int x;
	unsigned int y;
	unsigned int wx;
	unsigned int wy;
	unsigned int nbEx;
	int currentEx;
	int date;
	private:
	QBrush brush;
};

polarCalendar::polarCalendar(QWidget *parent) : QGraphicsView(parent)
{
	QDate tmp = QDate::currentDate();
	firstDate = QDate(tmp.year(), tmp.month(), 1);
	QGraphicsScene *scene = new QGraphicsScene(this);
	setSceneRect(0,-cellsize-10,10*cellsize,9*cellsize);
	setScene(scene);
	selection=NULL;
	previewitm=NULL;
}

void polarCalendar::initialize(polar4linuxInternals *internals0)
{
  internals=internals0;
  plotCalendar(); 
}

void polarCalendar::plotCalendar()
{
	gBrush.setStyle(Qt::SolidPattern);
	gBrush.setColor(internals->default_graph_configuration.colors.transpWhite);
	
	rs400_pdd_content toto;

	qDeleteAll( scene()->items() );
	previewitm=NULL;
	selection=NULL;
	
	//display month:
	scene()->addRect(0,-(cellsize+2),(cellsize+2)*7-2,cellsize,gPen,gBrush);
	scene()->addText( QDate::longMonthName(firstDate.month() )+" "+QString::number(firstDate.year()))-> setPos(2*cellsize,-(cellsize-2));
	
	scene()->addText(tr("-"))-> setPos(5*cellsize,-(cellsize-2));
	scene()->addText(tr("+"))-> setPos(5*cellsize+20,-(cellsize-2));

	//scene()->addRect(-32,32,30,32*6-2); 
	scene()->addRect(0,0,(cellsize+2)*7-2,30,gPen,gBrush);
	scene()->addText(tr("Mo"))-> setPos(5,5);
	scene()->addText(tr("Tu"))-> setPos(5+1*(cellsize+2),5);
	scene()->addText(tr("We"))-> setPos(5+2*(cellsize+2),5);
	scene()->addText(tr("Th"))-> setPos(5+3*(cellsize+2),5);
	scene()->addText(tr("Fr"))-> setPos(5+4*(cellsize+2),5);
	scene()->addText(tr("Sa"))-> setPos(5+5*(cellsize+2),5);
	scene()->addText(tr("Su"))-> setPos(5+6*(cellsize+2),5);


    QDate date(firstDate.year(), firstDate.month(), 1);

	int row=1;


	unsigned int timeInZones[10];
	unsigned int totalTime,totalEnergy;
	for (int i=0;i<10;i++) timeInZones[i]=0;
	totalTime=0;
	totalEnergy=0;
	while (date.month() == firstDate.month())
	{

		int weekDay = date.dayOfWeek();
		QString disp=internals->data_path+date.toString("yyyyMMdd")+".pdd";
		if (QFile::exists(disp)) //file exists
		{
			gBrush.setColor(internals->default_graph_configuration.colors.transpBlue);
			_readPDD( (char*)disp.toStdString().c_str(), toto);
			for (unsigned int j=0;j<toto.dayinfo.nbrExercises;j++)
			{
				totalTime+=toto.exerciseinfo[j].totalTime;
				totalEnergy+=toto.exerciseinfo[j].energy;
				timeInZones[0]+=toto.exerciseinfo[j].zone0Time;
				timeInZones[1]+=toto.exerciseinfo[j].zone1Time;
				timeInZones[2]+=toto.exerciseinfo[j].zone2Time;
				timeInZones[3]+=toto.exerciseinfo[j].zone3Time;
				timeInZones[4]+=toto.exerciseinfo[j].zone4Time;
				timeInZones[5]+=toto.exerciseinfo[j].zone5Time;
			}
		}
		else
		{
			toto.dayinfo.nbrExercises=0;
			gBrush.setColor(internals->default_graph_configuration.colors.transpWhite);
		}
		SimpleItem *tmpI=new SimpleItem(toto.dayinfo.nbrExercises,(cellsize+2)*(weekDay-1),(cellsize+2)*row,
																		cellsize,cellsize,
																		date.day(),gBrush);
		scene()->addItem(tmpI);

		if (weekDay%7==0 || date.addDays(1).month() != firstDate.month() )
		{
			//plot stats
			if (totalTime!=0)
			{
				int totaltaille=(totalTime/36000.f)*80;
		
				int lastY=(cellsize+2)*7+10;
				gBrush.setColor(internals->default_graph_configuration.colors.c0);
				float frac=timeInZones[5]/(float)totalTime;
				scene()->addRect(lastY,(cellsize+2)*row+(cellsize-10),totaltaille*frac,10,gPen,gBrush);
				lastY+=totaltaille*frac;
		
				gBrush.setColor(internals->default_graph_configuration.colors.c1);
				frac=timeInZones[4]/(float)totalTime;
				scene()->addRect(lastY,(cellsize+2)*row+(cellsize-10),totaltaille*frac,10,gPen,gBrush);
				lastY+=totaltaille*frac;
		
				gBrush.setColor(internals->default_graph_configuration.colors.c2);
				frac=timeInZones[3]/(float)totalTime;
				scene()->addRect(lastY,(cellsize+2)*row+(cellsize-10),totaltaille*frac,10,gPen,gBrush);
				lastY+=totaltaille*frac;
		
				gBrush.setColor(internals->default_graph_configuration.colors.c3);
				frac=timeInZones[2]/(float)totalTime;
				scene()->addRect(lastY,(cellsize+2)*row+(cellsize-10),totaltaille*frac,10,gPen,gBrush);
				lastY+=totaltaille*frac;
		
				gBrush.setColor(internals->default_graph_configuration.colors.c4);
				frac=timeInZones[1]/(float)totalTime;
				scene()->addRect(lastY,(cellsize+2)*row+(cellsize-10),totaltaille*frac,10,gPen,gBrush);
				lastY+=totaltaille*frac;
		
				gBrush.setColor(internals->default_graph_configuration.colors.c5);
				frac=timeInZones[0]/(float)totalTime;
				scene()->addRect(lastY,(cellsize+2)*row+(cellsize-10),totaltaille*frac,10,gPen,gBrush);
				lastY+=totaltaille*frac;
		
				char duration[10];
				timetostr(duration, totalTime);
				QString du=QString(duration);
				QGraphicsTextItem* tmp = scene()->addText(du);
				tmp-> setPos((cellsize+2)*7+5,(cellsize+2)*row);
				tmp->setZValue(1);

				QGraphicsTextItem* tmp2 = scene()->addText(QString::number(totalEnergy)+" kcal");
				tmp2-> setPos((cellsize+2)*7+5,(cellsize+2)*row+10);
				tmp2->setZValue(1);
			}

			for (int i=0;i<10;i++) timeInZones[i]=0;
			totalTime=0;
			totalEnergy=0;
			row++;
		}
        date = date.addDays(1);
	}
}

void polarCalendar::drawBackground ( QPainter * painter, const QRectF & /*rect*/ )
{
	QPointF orig=mapToScene(0.,0.);
	QRectF test=sceneRect();
	QPixmap pim(internals->CalendarBGimages_path);
	painter->drawPixmap(orig.x(),orig.y(),pim.scaled(QSize(width(),height()),Qt::IgnoreAspectRatio));
}

void polarCalendar::resizeEvent ( QResizeEvent * /*event*/ )
{
	//QPixmap pim("./images/path.jpeg");
	//QGraphicsPixmapItem *pixm=scene()->addPixmap(pim);
	//pixm->moveBy(-30,-30);
	//pixm->setZValue(-5000000); //if not, it can be on top of others!
	//scene()->setBackgroundBrush(pim.scaled(QSize(width(),height()),Qt::IgnoreAspectRatio));
}

void polarCalendar::deselectItem(SimpleItem* itm)
{
	if (itm!=NULL) itm->release();
	invalidatePreview();
}


void polarCalendar::selectItem(SimpleItem* itm)
{
	itm->select();
}

void polarCalendar::showPreview()
{
	if (previewitm==NULL)
	{
		previewitm= scene()->addPixmap(QPixmap::fromImage(internals->imagePreview));
		int x=selection->x+0.5*cellsize;
		int y=selection->y+0.5*cellsize-2*cellsize;
		//choose preview position
		int x0,y0;
		x0=x+200-20>width()?x-200:x;
		y0=y+150+100+100>height()?y-200:y;
		previewitm->moveBy(x0,y0+100);
		previewitm->setZValue(10000);
	}
}

void polarCalendar::invalidatePreview()
{
	if (previewitm!=NULL) {scene()->removeItem((QGraphicsItem*)previewitm); previewitm=NULL;}
}

void polarCalendar::mouseMoveEvent ( QMouseEvent * event )
{
	QPoint pt0 = event->pos();
	QPointF pt = mapToScene(event->pos());

	SimpleItem* oldselection=selection;
	int lastExNum=selectedExercise;
	selection=dynamic_cast<SimpleItem*>(itemAt(pt0.x(),pt0.y()));

	deselectItem(oldselection);
	if (selection!=NULL)
	{
		selectItem(selection);
		selectedDate=firstDate.addDays(selection->date-1);
		selectedExercise=selection->setCurrentExercise(pt);
		QString disp=internals->data_path+selectedDate.toString("yyyyMMdd")+".pdd";

		if (oldselection!=selection || lastExNum!=selectedExercise)
		{
			invalidatePreview();
			deselectItem(selection); selectItem(selection); //redraw
			emit newdatePrev(selectedDate,selectedExercise);
		}
		if (QFile::exists(disp)) showPreview();
	}
}

void polarCalendar::redraw() //slot
{
	deselectItem(selection);
	plotCalendar();
}

void polarCalendar::mousePressEvent(QMouseEvent *event)
{
	QPoint pt0 = event->pos();
	QPointF pt = mapToScene(pt0);
		
	QPoint ini(event->x(),event->y());
	QPointF pta = mapToGlobal(ini);

	if (selection!=NULL && selectedExercise>=1 && selectedExercise<=10) //show exercise
	{
		QMenu * menu = new QMenu(tr("name"), this);
		connect(menu,SIGNAL(aboutToHide()), this, SLOT(redraw()));
		
		QAction *ac = new QAction(tr("show exercise ")+QString::number(selectedExercise), this);
		ac->setData(0);
		menu->addAction(ac);
		connect(ac, SIGNAL(triggered()), this, SLOT(triggerNewDate()));

		if (internals->plotW->NumberOfGraphs()!=0)
		{
			if (internals->plotW->NumberOfGraphs()>=1)
			{
				QAction *ac2 = new QAction(tr("add exercise ")+QString::number(selectedExercise)+tr(" for comparison"), this);
				ac2->setData(1);
				menu->addAction(ac2);
				connect(ac2, SIGNAL(triggered()), this, SLOT(triggerNewDate()));
			}

			QAction *ac3 = new QAction(tr("add exercise ")+QString::number(selectedExercise)+tr(" (new plot)"), this);
			ac3->setData(2);
			menu->addAction(ac3);
			connect(ac3, SIGNAL(triggered()), this, SLOT(triggerNewDate()));
		}
		menu->addSeparator();
		QAction *ac4 = new QAction(tr("delete exercise ")+QString::number(selectedExercise), this);
		ac4->setData(3);
		menu->addAction(ac4);
		connect(ac4, SIGNAL(triggered()), this, SLOT(triggerDeleteExercise()));
		
		
		menu->move(pta.x(), pta.y());
		menu->show();
	}
	else if (selection!=NULL && !selection->isOn(pt)) {redraw();}
	else
	{
		//minus
		if (fabs(pt.x()-5*cellsize)<10 && pt.y()>-(cellsize-2) && pt.y()<-8)
		{
			firstDate=firstDate.addMonths(-1);
			plotCalendar();
		}
		//plus
		else if (fabs(pt.x()-(5*cellsize+20 ))<10 && pt.y()>-(cellsize-2) && pt.y()<-8)
		{
			firstDate=firstDate.addMonths(1);
			plotCalendar();
		}
		//week sum
		else
		{
			int col = (int)pt.x()/(cellsize+2);
			int row = (int)pt.y()/(cellsize+2)-1;
			QMenu * menu = new QMenu(tr("name"), this);

			if (col>=7 && row>=0 && row<=5) //week sum
			{
				int date = row*7-firstDate.dayOfWeek()+2;
				selectedDate=firstDate.addDays(date-1);

				QAction *ac = new QAction(tr("Display week sum. "), this);
				menu->addAction(ac);
				connect(ac, SIGNAL(triggered()), this, SLOT(triggerWeekSum()));
				menu->move(pta.x(), pta.y());
				menu->show();
			}
		}
	}
}

void polarCalendar::triggerNewDate()
{
	deselectItem(selection);
	QAction *tmp = qobject_cast<QAction*>(sender());
	int method=tmp->data().toInt();
	emit newdate(selectedDate,selectedExercise,method);
}

void polarCalendar::triggerWeekSum()
{
	deselectItem(selection);
	emit newSummary(selectedDate);
}

void polarCalendar::triggerDeleteExercise()
{
	switch( QMessageBox::question( NULL, "",
        QObject::tr("This will permanently delete this exercise from the disk.\n"
        "Are you sure?"),
        QObject::tr("Yes"),
        QObject::tr("No"), 0, 0, 1 ) ) {
    case 0: // The user clicked yes
				{
					std::string filenameHRM=internals->data_path.toStdString()+buildHRMfilename(
					selectedDate.year()-2000,selectedDate.month(),selectedDate.day(),selectedExercise);
					
					std::string filenamePDD=internals->data_path.toStdString()+buildPDDfilename(
					selectedDate.year(),selectedDate.month(),selectedDate.day());

					//std::cout<<"delete:"<<selectedExercise<<std::endl;
					//std::cout<<filenameHRM<<std::endl;
					//std::cout<<filenamePDD<<std::endl;
					
					bool success=QFile::remove(QString(filenameHRM.c_str()));
					if (success)
					{
						rs400_pdd_content dayContent;
						_readPDD(filenamePDD.c_str(),dayContent);
						
						dayContent.dayinfo.nbrExercises--;
						if (dayContent.dayinfo.nbrExercises==0) QFile::remove(QString(filenamePDD.c_str()));
						else
						{
							//indexes will changed, rename
							for (unsigned int i=selectedExercise;i<dayContent.exerciseinfo.size();i++)
							{
								//generate new name
								QString oldName = QString(dayContent.exerciseinfo[i].exoHRMfile);
								QString newName = QString(buildHRMfilename(selectedDate.year()-2000,selectedDate.month(),selectedDate.day(),i).c_str());
								strcpy(dayContent.exerciseinfo[i].exoHRMfile,newName.toStdString().c_str());
								QFile::rename(internals->data_path+oldName,internals->data_path+newName);
								
							}
							dayContent.exerciseinfo.erase (dayContent.exerciseinfo.begin()+selectedExercise-1);
							_savePDD(filenamePDD.c_str(),dayContent);
						}
						plotCalendar();
					}
				}
        break;
    case 1: // The user clicked no, cancel
        // exit
        break;
    }
}

